package com.tarena.luban.demo.all.adapter.consumer;

import com.tarena.luban.commons.pojo.order.dto.OrderAddDTO;
import com.tarena.luban.demo.all.service.IOrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
@RocketMQMessageListener(topic="order-add-topic",consumerGroup = "gg3")
public class OrderConsumer implements RocketMQListener<OrderAddDTO> {
    @Autowired
    private IOrderService orderService;

    /**
     * 保存商品缓存 tmall:product:prefix:+productId
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    //set get setnx
    @Override
    public void onMessage(OrderAddDTO message) {
        //1. 先抢锁 设计锁的key值,重复消费的消息,key相同的
        //订单消息 应该保存了唯一数值 orderSN
        String orderSn= UUID.randomUUID().toString();
        String lockKey="message:lock:"+orderSn;
        String lockValue=new Random().nextInt(9000)+1000+"";
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        //ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
        //set
        //opsForValue.set();
        //get
        //opsForValue.get();
        //incr
        //opsForValue.increment();
        //setnx setIfAbsent(); setnx key value  expire key 10
        try {
            Boolean tryLock = opsForValue.setIfAbsent(lockKey, lockValue, 10, TimeUnit.SECONDS);
            int count =1;
            while (!tryLock) {
                if (count==5){
                    return;
                }
                //等待5秒钟 再抢 为什么等5秒,为什么不等8秒 5.5秒
                Thread.sleep(5000);
                tryLock = opsForValue.setIfAbsent(lockKey, lockValue, 10, TimeUnit.SECONDS);
                count++;
            }
            orderService.orderAdd(message);
        }catch (Exception e){
            log.error("执行消费逻辑异常",e);
        }finally {
            String code = opsForValue.get(lockKey);
            if (code!=null && code.equals(lockValue)){
                stringRedisTemplate.delete(lockKey);
            }
        }
    }
}
